package com.panopset.sf;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.JDialog;
import javax.swing.JFrame;

import com.panopset.Numbers;
import com.panopset.compat.Geometry;
import com.panopset.compat.Logz;
import com.panopset.sf.env.Screener;

/**
 * Usually used for about boxes, a PopupBox is a modeless dialog that disappears
 * when the user does a mouse click or presses any key.
 * 
 * @author Karl Dinwiddie
 */
public abstract class PopupBox {

	/**
	 * @return PopupBox size.
	 */
	public abstract Dimension createSize();

	/**
	 * @return PopupBox display component.
	 */
	public abstract Component createComponent();

	/**
	 * Size.
	 */
	private Dimension sz;

	/**
	 * 
	 * @return Size.
	 */
	public Dimension getSize() {
		if (sz == null) {
			sz = createSize();
		}
		return sz;
	}

	/**
	 * Parent frame.
	 */
	private JFrame parent;

	/**
	 * Set a parent frame for positioning.
	 * 
	 * @param frame
	 *            Parent frame.
	 */
	public final void setParent(final JFrame frame) {
		this.parent = frame;
	}

	/**
	 * Internal component.
	 */
	private Component component;

	/**
	 * 
	 * @return Internal component.
	 */
	private Component getComponent() {
		if (component == null) {
			component = createComponent();
		}
		return component;
	}

	/**
	 * Links.
	 */
	private final List<Link> links = new ArrayList<Link>();

	/**
	 * Add a link to the display area.
	 * 
	 * @param area
	 *            Area where link will be hot.
	 * @param urlString
	 *            URL as String.
	 */
	public final void addLink(final Rectangle area, final String urlString) {
		links.add(new Link(area, urlString));
	}

	/**
	 * Dispose popup box.
	 */
	public final void dispose() {
		if (dialog != null) {
			dialog.dispose();
			dialog = null;
		}
	}

	/**
	 * Show popup box.
	 */
	public final void show() {
		getDialog().setVisible(true);
	}

	/**
	 * Popup box dialog.
	 */
	private JDialog dialog;

	/**
	 * @return Popup box dialog.
	 */
	private JDialog getDialog() {
		if (dialog == null) {
			dialog = new JDialog();
			dialog.setUndecorated(true);
			dialog.setSize(getSize());
			if (parent == null) {
				dialog.setLocation(new Screener().centerInScreen(dialog
						.getSize()));
			} else {
				dialog.setLocation(new Geometry().getCenterRectUpperLeftPoint(
						dialog.getSize(), parent.getBounds()));
			}
			dialog.add(getComponent());
			dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
			getComponent().addKeyListener(new KeyAdapter() {

				@Override
				public void keyPressed(final KeyEvent e) {
					PopupBox.this.dispose();
				}

			});
			getComponent().addMouseListener(new MouseAdapter() {

				/**
				 * Last click time.
				 */
				private long lastClickTime = 0;

				@Override
				public void mousePressed(final MouseEvent e) {
					for (Link link : links) {
						if (new Geometry().pointInRect(e.getPoint(),
								link.getArea())) {
							return;
						}
					}
					PopupBox.this.dispose();
				}

				@Override
				public void mouseClicked(final MouseEvent e) {
					for (Link link : links) {
						if (new Geometry().pointInRect(e.getPoint(),
								link.getArea())) {
							synchronized (this) {
								long time = new Date().getTime();
								if (time - lastClickTime

								> Numbers.Integers.QUARTER_SECOND.getValue()) {
									try {
										Desktop.getDesktop().browse(
												new URI(link.getUrl()));
									} catch (Exception ex) {
										Logz.log(ex);
									}
								}
								lastClickTime = time;
							}
							return;
						}
					}
					PopupBox.this.dispose();
				}

			});
			getComponent().addMouseMotionListener(new MouseMotionAdapter() {

				@Override
				public void mouseMoved(final MouseEvent e) {
					for (Link link : links) {
						if (new Geometry().pointInRect(e.getPoint(),
								link.getArea())) {
							getComponent().setCursor(

							Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
							return;
						}
					}
					getComponent().setCursor(
							Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
				}

			});
		}
		return dialog;
	}
}
